package com.health.trans.config.dataSource;

import cn.hutool.core.util.StrUtil;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * @author nqlz
 */
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = DynamicDataSourceProperties.PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties(value = {DynamicDataSourceProperties.class, JpaProperties.class})
@Slf4j
@RequiredArgsConstructor
@Primary
public class DataSourceAutoConfig {

    protected final ApplicationContext applicationContext;
    protected final JpaProperties jpaProperties;
    protected final EntityManagerFactoryBuilder builder;
    private final HibernateProperties hibernateProperties;
    private final String mysqlKey = "mysql";
    private final DynamicRoutingDataSource dynamicRoutingDataSource;
    private final DynamicDsConf dynamicDsConf;

    private Map<String, Object> getVendorProperties(String dialect) {
        Map<String, String> map = new HashMap<>();
        // 设置对应的数据库方言
        map.put("hibernate.dialect", dialect);
        return hibernateProperties.determineHibernateProperties(map, new HibernateSettings());
    }

    @PostConstruct
    public void dataSourceCreate() {
        ConfigurableApplicationContext context = (ConfigurableApplicationContext) applicationContext;
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();

        dynamicRoutingDataSource.getDataSources().forEach((dsName, dataSource) -> {
            BsDtSource bsDtSource = new BsDtSource(dsName, dataSource);
            DsProperty dsProperty = dynamicDsConf.getDsProperties().get(dsName);
            //方言校验
            String dialect = dsProperty.getDialect();
            if (StrUtil.isBlank(dsProperty.getDialect())) {
                if (dsProperty.getDriverClassName().contains(mysqlKey)) {
                    dialect = DialectConf.mysqlDialect;
                } else {
                    throw new RuntimeException("非MySQL数据库，必须写明使用方言。");
                }
            }
            bsDtSource.initDs(applicationContext, beanFactory, builder, getVendorProperties(dialect));
        });
    }

    static class BsDtSource extends AbstractBsDts {
        protected BsDtSource(String dataSourceName, DataSource dataSource) {
            super(dataSourceName, dataSource);
        }
    }

}
